﻿using AutoMapper;
using MD5Hash;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using RBAC.Api.Demain.Entities;
using RBAC.Api.Erroc;
using RBAC.Api.Infaction;
using RBAC.Api.Read.Command.RBAC;
using RBAC.Api.Read.Common;
using RBAC.Api.Read.Dto;
using System.Diagnostics;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace RBAC.Api.Read.CommandHandler.RBAC
{
    public class LoginCommandHandler : IRequestHandler<LoginCommand, APIResult<LoginDto>>
    {
        private readonly IBaseRepositry<User> dal;
        private readonly IBaseRepositry<Role> dal2;
        private readonly IBaseRepositry<UserRole> dal3;
        private readonly IMapper mapper;
        private readonly ILogger<LoginCommandHandler> _logger;
        private readonly IConfiguration _config;
        private readonly TokenServices tokenServices;

        public LoginCommandHandler(IBaseRepositry<User> baseRepositry,
                                   IBaseRepositry<Role> baseRepositry1,
                                   IBaseRepositry<UserRole> baseRepositry2,
                                   IMapper mapper,
                                   ILogger<LoginCommandHandler> logger,
                                   IConfiguration config,
                                   TokenServices tokenServices)
        {
            dal = baseRepositry;
            dal2 = baseRepositry1;
            dal3 = baseRepositry2;
            this.mapper = mapper;
            _logger = logger;
            _config = config;
            this.tokenServices = tokenServices;
        }
        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task<APIResult<LoginDto>> Handle(LoginCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = Stopwatch.StartNew();
            APIResult<LoginDto> result = new APIResult<LoginDto>();

            try
            {
                _logger.LogInformation("开始处理用户登录请求: {Username}", request.Username);

                //获取用户
                var list = dal.GetAll().AsTracking().FirstOrDefault(x => x.Username == request.Username);

                if (list == null)
                {
                    result.Code = ResultCode.Fail;
                    result.Message = "用户不存在";
                    _logger.LogWarning($"登录失败: 用户 {request.Username} 不存在", request.Username);
                    return Task.FromResult(result);
                }

                if (list.Password != request.Password.GetMD5())
                {
                    result.Code = ResultCode.Fail;
                    result.Message = "密码错误";
                    _logger.LogWarning($"登录失败: 用户 {request.Username} 密码错误", request.Username);
                    return Task.FromResult(result);
                }

                var userDto = mapper.Map<LoginDto>(list);

                //获取角色id
                var roleId = dal3.GetAll().Where(x => x.UserId == list.Id).Select(x => x.RoleId).ToList();
                userDto.RoleId = string.Join(",", roleId);
                userDto.RoleName = string.Join(",", dal2.GetAll().Where(x => roleId.Contains(x.Id)).Select(x => x.RoleName));

                result.Code = ResultCode.Success;
                result.Message = "登录成功";

                //生成访问Token
                result.Token = tokenServices.GenerateJwtToken(userDto);
                //获取刷新Token
                result.RefreshToken = tokenServices.GenRefreshToken(userDto.Id);

                result.Data = userDto;

                _logger.LogInformation("用户 {request. Username} 登录成功, 角色: { Roles}", request.Username, userDto.RoleName);
                return Task.FromResult(result);
            }
            catch (Exception ex)
            {
                // 记录异常
                _logger.LogError(ex, "用户登录时发生错误: {Username}, 错误信息: {Message}",
                    request.Username, ex.Message);

                // 设置失败结果
                result.Code = ResultCode.Fail;
                result.Message = $"登录失败: {ex.Message}";
                return Task.FromResult(result);
            }
            finally
            {
                stopwatch.Stop();
                _logger.LogInformation("处理用户登录请求完成, 耗时: {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
            }
        }

        /// <summary>
        /// 生成JWT令牌
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public string GenerateJwtToken(LoginDto user)
        {
            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JwtSettings:SecretKey"]));
            var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

            var claims = new[]
            {
                new Claim("Username", user.Username),
                new Claim("Nickname", user.Name),
                new Claim("UserId", user.Id.ToString()),
                new Claim("RoleId", user.RoleId.ToString()),
                new Claim("RoleName", user.RoleName)
            };

            var token = new JwtSecurityToken(
                issuer: _config["JwtSettings:Issuer"],
                audience: _config["JwtSettings:Audience"],
                claims: claims,
                expires: DateTime.Now.AddMinutes(120),
                signingCredentials: credentials
            );

            return new JwtSecurityTokenHandler().WriteToken(token);
        }
    }
}
